<?php
/**
 * ShopEx licence
 *
 * @copyright  Copyright (c) 2005-2010 ShopEx Technologies Inc. (http://www.shopex.cn)
 * @license  http://ecos.shopex.cn/ ShopEx License
 */

/**
 * allinpay担保交易支付网关（国内）
 * @auther shopex ecstore dev dev@shopex.cn
 * @version 0.1
 * @package ectools.lib.payment.plugin
 */
final class weixin_payment_plugin_wxallinpaysdk extends ectools_payment_app implements ectools_interface_payment_app {

	/**
	 * @var string 支付方式名称
	 */
	public $name = '通联微信支付sdk';
	/**
	 * @var string 支付方式接口名称
	 */
	public $app_name = '通联微信支付sdk';
	 /**
	 * @var string 支付方式key
	 */
	public $app_key = 'wxallinpaysdk';
	/**
	 * @var string 中心化统一的key
	 */
	public $app_rpc_key = 'wxallinpaysdk';
	/**
	 * @var string 统一显示的名称
	 */
	public $display_name = '通联微信支付sdk';
	/**
	 * @var string 货币名称
	 */
	public $curname = 'CNY';
	/**
	 * @var string 当前支付方式的版本号
	 */
	public $ver = '1.0';
	/**
	 * @var string 当前支付方式所支持的平台
	 */
	public $platform = 'iswap';

	/**
	 * @var array 扩展参数
	 */
	public $supportCurrency = array("CNY"=>"01");

	/**
	 * 构造方法
	 * @param null
	 * @return boolean
	 */
	public function __construct($app){
		parent::__construct($app);

		$this->notify_url = kernel::base_url(1).'/index.php/openapi/weixin/wxallinpaysdk';
		#test
		if (preg_match("/^(http):\/\/?([^\/]+)/i", $this->notify_url, $matches))
		{
			$this->notify_url = str_replace('http://','',$this->notify_url);
			$this->notify_url = preg_replace("|/+|","/", $this->notify_url);
			$this->notify_url = "http://" . $this->notify_url;
		}
		else
		{
			$this->notify_url = str_replace('https://','',$this->notify_url);
			$this->notify_url = preg_replace("|/+|","/", $this->notify_url);
			$this->notify_url = "https://" . $this->notify_url;
		}
		$this->callback_url = kernel::openapi_url('openapi.ectools_payment/parse/weixin/weixin_payment_plugin_wxpay', 'callback');
		if (preg_match("/^(http):\/\/?([^\/]+)/i", $this->callback_url, $matches))
		{
			$this->callback_url = str_replace('http://','',$this->callback_url);
			$this->callback_url = preg_replace("|/+|","/", $this->callback_url);
			$this->callback_url = "http://" . $this->callback_url;
		}
		else
		{
			$this->callback_url = str_replace('https://','',$this->callback_url);
			$this->callback_url = preg_replace("|/+|","/", $this->callback_url);
			$this->callback_url = "https://" . $this->callback_url;
		}

		$this->submit_method = 'POST';
		$this->submit_charset = 'utf-8';
	}

	/**
	 * 后台支付方式列表关于此支付方式的简介
	 * @param null
	 * @return string 简介内容
	 */
	public function admin_intro(){
		return app::get('ectools')->_('通联微信支付a');
	}

	 /**
	 * 后台配置参数设置
	 * @param null
	 * @return array 配置参数列表
	 */
	public function setting(){
		// 公众账号
		$publicNumbersInfo = app::get('weixin')->model('bind')->getList('appid,name',array('appid|noequal'=>''));
		$publicNumbers = array();
		foreach($publicNumbersInfo as $row){
			$publicNumbers[$row['appid']] = $row['name'];
		}

		return array(
			'pay_name'=>array(
				'title'=>app::get('ectools')->_('支付方式名称'),
				'type'=>'string'
				),
			'appid'=>array(
				 'title'=>app::get('weixin')->_('appid'),
				 'type'=>'string',
				 'validate_type' => 'required',
			 ),
			'cusid'=>array(
				'title'=>app::get('weixin')->_('cusid'),
				'type'=>'string',
				'validate_type' => 'required',
			),
			'key'=>array(
				'title'=>app::get('weixin')->_('key'),
				'type'=>'string',
				'validate_type' => 'required',
			),
			'order_by' =>array(
				'title'=>app::get('ectools')->_('排序'),
				'type'=>'string',
				'label'=>app::get('ectools')->_('整数值越小,显示越靠前,默认值为1'),
			),
			'pay_brief'=>array(
				'title'=>app::get('ectools')->_('支付方式简介'),
				 'type'=>'textarea',
			),
			'pay_desc'=>array(
				'title'=>app::get('ectools')->_('描述'),
				'type'=>'html',
				'includeBase' => true,
			),
			'pay_type'=>array(
				 'title'=>app::get('ectools')->_('支付类型(是否在线支付)'),
				 'type'=>'radio',
				 'options'=>array('false'=>app::get('ectools')->_('否'),'true'=>app::get('ectools')->_('是')),
				 'name' => 'pay_type',
			),
			'status'=>array(
				'title'=>app::get('ectools')->_('是否开启此支付方式'),
				'type'=>'radio',
				'options'=>array('false'=>app::get('ectools')->_('否'),'true'=>app::get('ectools')->_('是')),
				'name' => 'status',
			),
		);
	}
	/**
	 * 通联微信支付方式列表关于此支付方式的简介
	 * @param null
	 * @return string 简介内容
	 */
	public function intro(){
		return app::get('ectools')->_('通联支付客户自定义描述');
	}

	/**
	 * 提交支付信息的接口
	 * @param array 提交信息的数组
	 * @return mixed false or null
	 */
	public function dopay($payment)
	{
		//金额
		$price = bcmul($payment['cur_money'],100,0);
		$appid      = trim($this->getConf('appid',    __CLASS__));//通联平台分配的APPID
		$cusid      = trim($this->getConf('cusid',    __CLASS__));//通联平台分配的商户号
		$key     = trim($this->getConf('key',      __CLASS__));
		$url = "https://vsp.allinpay.com/apiweb/weixin/pay";//生产环境
		// $url = "http://113.108.182.3:10080/apiweb/weixin/pay";//测试环境
		$body=strval( str_replace(' ', '', (isset($payment['body']) && $payment['body']) ? $payment['body'] : app::get('weixin')->_('网店订单') ) );
		$body=mb_substr($body,0,40,'utf-8');//防止数据过长导致支付失败
		$body = str_replace('+','',$body);
		$timeStamp=strval(time());

		$parameters = array(
			'appid' => strval($appid), //应用ID 00002251
			'cusid' => strval($cusid), //商户号162605048168713
			'version' => '11',         //版本号
			'trxamt' => $price,           //交易金额 单位为分
			'reqsn' => strval($payment['payment_id']), //订单号,自行生成
			'paytype' => '2',          //交易方式 0:扫码支付 1:js支付 2:微信app支付 3:微信刷卡支付
			'randomstr' => (string)$timeStamp,   //商户自行生成的随机字符串
			'notify_url' => strval($this->notify_url),//交易结果通知地址 接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数
			'limit_pay' => 'no_credit',//指定支付方式,no_credit--指定不能使用信用卡支付
			'body' => $body,           //订单商品名称，为空则以商户名作为商品名称
			'sub_appid' => 'wx2f66da2072f4240c',//新添加参数？测试
		);
		$parameters['sign'] = $this->SignArray($parameters, $key);
		$xml                = $this->ToUrlParams($parameters);
		logger::info('wxallinpaysdk的请求参数:'.var_export($xml, 1));
		$response           = $this->request($url,$xml);
		logger::info('wxallinpaysdk的返回值:'.var_export($response, 1));
		$result             = json_decode($response,1);
		logger::info('result:'.var_export($result, 1));
		$wxdata = json_decode($result['weixinstr'],1);
		// $wxdata['appid'] = $wxdata['appId'];
		// $wxdata['partnerid'] = $wxdata['partnerId'];
		// $wxdata['prepayid'] = $wxdata['prepayId'];
		// $wxdata['noncestr'] = $wxdata['nonceStr'];
		// $wxdata['timestamp'] = $wxdata['timeStamp'];
		// $wxdata['sign'] = $wxdata['paySign'];
		// $wxdata['pay_sign'] = $wxdata['sign'];
		// $wxdata['nonce_str'] = $wxdata['noncestr'];
		$wxdata['api_key'] = $key;
		// $wxdata['payment_id'] = $result['reqsn'];
		logger::info('wxallinpaysdk的dopay返回值:'.var_export($wxdata, 1));
		return $wxdata;exit;
	}

	/**
	 * 校验方法
	 * @param null
	 * @return boolean
	 */
	public function is_fields_valiad(){
		return true;
	}

	/**
	 * 支付后返回后处理的事件的动作
	 * @params array - 所有返回的参数，包括POST和GET
	 * @return null
	 */
	public function callback(&$in)
	{
		$cusid     = trim($this->getConf('cusid',    __CLASS__));
		$key        = trim($this->getConf('key',      __CLASS__));
		logger::info('通联支付网关请求参数:'.var_export($in, 1));
		$in = $in['weixin_postdata'];
		$insign = $in['sign'];
		unset($in['sign']);

		if( $in['trxstatus'] == '0000')
		{
			if( $insign == strtoupper($this->SignArray( $in, $key)))
			{
				$objMath = kernel::single('ectools_math');
				$money   = $objMath->number_multiple(array($in['trxamt'], 0.01));
				$ret['payment_id' ] = $in['cusorderid'];
				$ret['account']     = $cusid;
				$ret['bank']        = app::get('wap')->_('通联支付sdk');
				$ret['pay_account'] = $in['acct'];
				$ret['currency']    = 'CNY';
				$ret['money']       = $money;
				$ret['paycost']     = '0.000';
				$ret['cur_money']   = $money;
				$ret['trade_no']    = $in['transaction_id'];
				$ret['t_payed']     = strtotime($in['paytime']) ? strtotime($in['paytime']) : time();
				$ret['pay_app_id']  = "wxallinpaysdk";
				$ret['pay_type']    = 'online';
				// $ret['memo']        = $in['attach'];
				$ret['status']      = 'succ';

			}else{
				$ret['status'] = 'failed';
			}
		}else{
			$ret['status'] = 'failed';
		}
		return $ret;
	}
	//交易查询
	public function query($payment_id){
		$url = 'https://vsp.allinpay.com/apiweb/weixin/query';
		$key     = trim($this->getConf('key',      __CLASS__));
		$params = array();
		$params["cusid"] = trim($this->getConf('cusid',    __CLASS__));//通联平台分配的商户号
	    $params["appid"] = trim($this->getConf('appid',    __CLASS__));//通联平台分配的APPID
	    $params["version"] = '11';
	    $params["reqsn"] = $payment_id;
	    $params["randomstr"] = strval(time());//
	    $params["sign"] = $this->SignArray($params,$key);//签名
	    $paramsStr = $this->ToUrlParams($params);
	    $rsp = $this->request($url, $paramsStr);
	    $rspArray = json_decode($rsp, 1);
	    logger::info('wxallinpaysdk的query返回值:'.var_export($rspArray, 1));
	    if($rspArray['retcode'] =='SUCCESS' && $rspArray['trxstatus'] =='0000' ){
	    	return true;
	    }else{
	    	return false;
	    }
	}
	/**
	 * 生成支付表单 - 自动提交
	 * @params null
	 * @return null
	 */
	/**
     * 支付成功回打支付成功信息给支付网关
     */
    function ret_result($paymentId){
        $ret = array('return_code'=>'SUCCESS','return_msg'=>'');
        $ret = $this->arrayToXml($ret);
        echo $ret;exit;
    }
	public function gen_form()
	{
	  return '';
	}


	protected function get_html(){
		header("Content-Type: text/html;charset=".$this->submit_charset);

		if( $this->fields['order_id'] ){
		  $success_url = app::get('wap')->router()->gen_url(array('app'=>'b2c','ctl'=>'wap_paycenter','act'=>'result_pay','full'=>1,'arg0'=>$this->fields['order_id'],'arg1'=>'true'));
		  $failure_url = app::get('wap')->router()->gen_url(array('app'=>'b2c','ctl'=>'wap_paycenter','act'=>'index','full'=>1,'arg0'=>$this->fields['order_id']));
		}else{
		  $success_url = app::get('wap')->router()->gen_url(array('app'=>'b2c','ctl'=>'wap_member','act'=>'balance','full'=>1));
		  $failure_url = app::get('wap')->router()->gen_url(array('app'=>'b2c','ctl'=>'wap_member','act'=>'index','full'=>1));
		}
		$strHtml = '
				<html>
					<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
					<title>微信安全支付</title>
					<script language="javascript">
								//调用微信JS api 支付
								function jsApiCall()
								{
									WeixinJSBridge.invoke(
										"getBrandWCPayRequest",
										'.$this->fields['jsApiParameters'].',
										function(res){
											// WeixinJSBridge.log(res.err_msg);
											if(res.err_msg=="get_brand_wcpay_request:ok"){
												window.location.href = "' . $success_url . '";
											}else{
											//  alert(res.err_msg);
												window.location.href = "' . $failure_url . '";
											}
											// alert(res.err_code+res.err_desc+res.err_msg);
										}
									);
								}

								function callpay()
								{
									if (typeof WeixinJSBridge == "undefined"){
										if( document.addEventListener ){
											document.addEventListener("WeixinJSBridgeReady", jsApiCall, false);
										}else if (document.attachEvent){
											document.attachEvent("WeixinJSBridgeReady", jsApiCall);
											document.attachEvent("onWeixinJSBridgeReady", jsApiCall);
										}
									}else{
										jsApiCall();
									}
								}
								callpay();
					</script>
					<body>
				 <button type="button" onclick="callpay()" style="display:none;">微信支付</button>
				 </body>
				</html>
			';
		return $strHtml;
	}

	/**
	 * 生成签名
	 * @param mixed $form 包含签名数据的数组
	 * @param mixed $key 签名用到的私钥
	 * @access private
	 * @return string
	 */
	public function _get_mac($key){
		ksort($this->fields);
		reset($this->fields);
		$mac= "";
		foreach($this->fields as $k=>$v){
			$mac .= "&{$k}={$v}";
		}
		$mac = substr($mac,1);
		$mac = md5($mac.$key);  //验证信息
		return $mac;
	}

	/**
	 * 检验返回数据合法性
	 * @param mixed $form 包含签名数据的数组
	 * @param mixed $key 签名用到的私钥
	 * @access private
	 * @return boolean
	 */
	public function is_return_vaild($form,$key)
	{
		ksort($form);
		foreach($form as $k=>$v){
			if($k!='sign'&&$k!='sign_type'){
				$signstr .= "&$k=$v";
			}
		}

		$signstr = ltrim($signstr,"&");
		$signstr = $signstr.$key;

		if($form['sign']==md5($signstr)){
			return true;
		}
		#记录返回失败的情况
		logger::error(app::get('ectools')->_('支付单号：') . $form['out_trade_no'] . app::get('ectools')->_('签名验证不通过，请确认！')."\n");
		logger::error(app::get('ectools')->_('本地产生的加密串：') . $signstr);
		logger::error(app::get('ectools')->_('通联支付传递打过来的签名串：') . $form['sign']);
		$str_xml .= "<allinpayform>";
		foreach ($form as $key=>$value)
		{
			$str_xml .= "<$key>" . $value . "</$key>";
		}
		$str_xml .= "</allinpayform>";

		return false;
	}


	/**
	 * 将参数数组签名
	 */
	public function SignArray($array = array(),$appkey){
	  $array['key'] = $appkey;// 将key放到数组中一起进行排序和组装
	  ksort($array);
	  $blankStr = $this->ToUrlParams($array);
	  logger::info('wxallinpaysdk的排序和组装:'.var_export($blankStr, 1));
	  $sign = md5($blankStr);
	  return $sign;
	}
	
	public function ToUrlParams($array = array())
	{
	  $buff = "";
	  foreach ($array as $k => $v)
	  {
		if($v != "" && !is_array($v)){
		  $buff .= $k . "=" . $v . "&";
		}
	  }
	  
	  $buff = trim($buff, "&");
	  return $buff;
	}

	//发送请求操作仅供参考,不为最佳实践
	public function request($url,$params){
	  $ch = curl_init();
	  $this_header = array("content-type: application/x-www-form-urlencoded;charset=UTF-8");
	  curl_setopt($ch,CURLOPT_HTTPHEADER,$this_header);
	  curl_setopt($ch, CURLOPT_URL, $url);
	  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	  curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
	  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
	   
	  curl_setopt($ch, CURLOPT_POST, 1);
	  curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
	  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);//如果不加验证,就设false,商户自行处理
	  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
	   
	  $output = curl_exec($ch);
	  curl_close($ch);
	  return  $output;
	}


	/**
	 * 校验签名
	 * @param array 参数
	 * @param unknown_type appkey
	 */
	public static function ValidSign(array $array,$appkey){
	  $sign = $array['sign'];
	  unset($array['sign']);
	  $array['key'] = $appkey;
	  $mySign = $this->SignArray($array, $appkey);
	  return strtolower($sign) == strtolower($mySign);
	}

	/**
	 *  作用：生成签名
	 */
	public function getSign($Obj,$key)
	{
		foreach ($Obj as $k => $v)
		{
			$Parameters[$k] = $v;
		}
		//签名步骤一：按字典序排序参数
		ksort($Parameters);
		$String = $this->formatBizQueryParaMap($Parameters, false);
		//echo '【string1】'.$String.'</br>';
		//签名步骤二：在string后加入KEY
		$String = $String."&key=".$key;
		//echo "【string2】".$String."</br>";
		//签名步骤三：MD5加密
		$String = md5($String);
		//echo "【string3】 ".$String."</br>";
		//签名步骤四：所有字符转为大写
		$result_ = strtoupper($String);
		//echo "【result】 ".$result_."</br>";
		return $result_;
	}


	/**
	 *  作用：格式化参数，签名过程需要使用
	 */
	function formatBizQueryParaMap($paraMap, $urlencode)
	{
		$buff = "";
		ksort($paraMap);
		foreach ($paraMap as $k => $v)
		{
			if($urlencode)
			{
			   $v = urlencode($v);
			}
			//$buff .= strtolower($k) . "=" . $v . "&";
			$buff .= $k . "=" . $v . "&";
		}
		$reqPar;
		if (strlen($buff) > 0)
		{
			$reqPar = substr($buff, 0, strlen($buff)-1);
		}
		return $reqPar;
	}
	 /**
	 *  作用：以post方式提交xml到对应的接口url
	 */
	public function postXmlCurl($xml,$url,$second=30)
	{
		$res = kernel::single('base_httpclient')->post($url,$xml);
		return $res;
	}

	/**
	 *  作用：将xml转为array
	 */
	public function xmlToArray($xml)
	{
		//将XML转为array
		$array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
		return $array_data;
	}

	/**
	 *  作用：array转xml
	 */
	function arrayToXml($arr)
	{
		$xml = "<xml>";
		foreach ($arr as $key=>$val)
		{
			 if (is_numeric($val))
			 {
				$xml.="<".$key.">".$val."</".$key.">";

			 }
			 else
				$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
		}
		$xml.="</xml>";
		return $xml;
	}
}
